package com.sky.service.common.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sky.dto.CourierOrderCountDTO;
import com.sky.exception.MerchantNotFoundException;
import com.sky.mapper.common.MerchantMapper;
import com.sky.mapper.courier.CourierMapper;
import com.sky.mapper.courier.CourierTradeOrderMapper;
import com.sky.pojo.Courier;
import com.sky.pojo.CourierTradeOrder;
import com.sky.pojo.Merchant;
import com.sky.pojo.Orders;
import com.sky.service.common.OrderDispatchService;
import com.sky.websocket.WebSocketServer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;

/**
 * 订单调度业务实现
 *
 * @author zgp
 * @version V1.0
 * @date 2025-02-09 14:59
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderDispatchServiceImpl implements OrderDispatchService {
    private final MerchantMapper merchantMapper;
    private final CourierMapper courierMapper;
    private final CourierTradeOrderMapper courierTradeOrderMapper;
    private final WebSocketServer webSocketServer;
    private final RedisTemplate redisTemplate;


    @Override
    public Courier dispatch(Orders orders) {
        // 1. 查找符合条件骑手
        // 1.1 查询商家10km内在职骑手
        List<Courier> couriers = getCouriersByMerchant10Range(orders.getShopId());
        if (ObjectUtil.isNull(couriers)) {
            // 商家10km范围内暂未有骑手
            return null;
        }
        String todayDateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        List<Long> curIds = couriers.stream().map(o -> o.getId()).toList();
        // 1.2 统计骑手【待接单】、【待取货】、【待送货】的总订单数量
        List<CourierOrderCountDTO> courierOrderCountDTOList = courierMapper.selectCouriersOrdersNum(todayDateStr, curIds);
        Long minOrdersCount = courierOrderCountDTOList.stream().map(o -> o.getCount()).min(Long::compareTo).get();
        log.info("最小订单量：{}", minOrdersCount);
        // 1.3 过滤骑手订单量 <= 最小订单数+3, 且订单数量小于12单的骑手
        List<Long> resultCouriesIds = courierOrderCountDTOList.stream()
                .filter(o -> o.getCount() <= (minOrdersCount + 3))
                .filter(o -> o.getCount() <= 12)
                .map(o -> o.getId())
                .toList();
        // 1.4 如上述条件都不符合，从10km内在职骑手中随机派单
        if (CollUtil.isEmpty(resultCouriesIds)) {
            int randomIndex = new Random().nextInt(couriers.size());
            resultCouriesIds.add(couriers.get(randomIndex).getId());
        }
        // 1.3 找出评分最高的骑手
        Optional<Courier> maxScoreCourierOptional = couriers.stream()
                .filter(o -> resultCouriesIds.contains(o.getId()))
                .max((o1, o2) -> o2.getScore().compareTo(o1.getScore()));
        if (maxScoreCourierOptional.isEmpty()) {
            log.warn("未找到最高分骑手，couriers = {}", couriers);
            return null;
        }
        // 2. 生成运单
        saveCourierTradeOrder(maxScoreCourierOptional.get(), orders);

        // 3. 通知骑手
        webSocketServer.notifyCourier(orders.getNumber(), maxScoreCourierOptional.get().getId());
        // 4. 返回骑手数据
        return maxScoreCourierOptional.get();
    }

    /**
     * 保存运单数据
     *
     * @param courier 骑手
     * @param orders  订单
     */
    private void saveCourierTradeOrder(Courier courier, Orders orders) {
        Merchant merchant = merchantMapper.selectById(orders.getShopId());
        // 骑手提成计算：1公里内50%；超出1公里部分，少于3公里部分60%；超出3公里部分70%
        double deliveryFee = orders.getDeliveryFee().doubleValue();
        BigDecimal income = BigDecimal.valueOf(0.0);
        if (deliveryFee <= 3.0) {
            income = income.add(BigDecimal.valueOf(1.5));
        } else if (deliveryFee <= 5.0) {
            income = income.add(BigDecimal.valueOf(1.5))
                    .add(BigDecimal.valueOf(deliveryFee - 3).multiply(BigDecimal.valueOf(0.6)));
        } else {
            income = income.add(BigDecimal.valueOf(1.5))
                    .add(BigDecimal.valueOf(deliveryFee - 3).multiply(BigDecimal.valueOf(0.6)))
                    .add(BigDecimal.valueOf(deliveryFee - 5).multiply(BigDecimal.valueOf(0.7)));
        }
        // 构建运单对象
        CourierTradeOrder courierTradeOrder = CourierTradeOrder.builder()
                .totalAmount(orders.getAmount())
                .courierId(courier.getId())
                .remark(orders.getRemark())
                .shopAddress(merchant.getShopAddress())
                .orderNumber(orders.getNumber())
                .waybillStatus(CourierTradeOrder.DISPATCH_OK)
                .tradeCreateTime(LocalDateTime.now())
                .courierTelephone(courier.getTelephone())
                .customerAddress(orders.getAddress())
                .customerExpectedDeliveryTime(orders.getEstimatedDeliveryTime())
                .customerName(orders.getConsignee())
                .shopName(merchant.getShopName())
                .telephone(orders.getPhone())
                .toBeMealTime(orders.getMealTime())
                .income(income)
                .build();
        // 保存运单数据
        courierTradeOrderMapper.insert(courierTradeOrder);
    }

    /**
     * 获取距商家10km内的骑手数据
     *
     * @param shopId 商家id
     * @return 骑手列表
     */
    private List<Courier> getCouriersByMerchant10Range(Long shopId) {
        // 获取商家位置
        Merchant merchant = merchantMapper.selectById(shopId);
        if (ObjectUtil.isNull(merchant)) {
            throw new MerchantNotFoundException("商家不存在，id = " + shopId);
        }
        // 获取商家位置
        String merchantLocation = merchant.getLocation();
        // 获取所有骑手列表
        List<Courier> couriers = courierMapper.selectAllOnlineCouriers();
        // // 过滤10km内骑手
        // List<Courier> filteredCouriers = couriers.stream().filter(c -> {
        //     String curLocation = c.getCurLocation();
        //     double distance = Double.valueOf(MapUtils.gaodeTwoPointCostDistanceAndTimeByLngLat(merchantLocation, curLocation).get("distance"));
        //     return distance < 10000;
        // }).toList();

        // 过滤10km内骑手：改用redis中geo类型进行测距
        // 将在线骑手经纬度位置写入redis
        for (Courier courier : couriers) {
            String[] lnglat = courier.getCurLocation().split(",");
            redisTemplate.opsForGeo()
                    .add("onlin_courier", new Point(Double.parseDouble(lnglat[0]), Double.parseDouble(lnglat[1])), "courier_" + courier.getId());
        }
        // 调用redis geo数据类型的radius功能进行测距
        String[] merchantLnglat = merchantLocation.split(",");
        Point point = new Point(Double.parseDouble(merchantLnglat[0]), Double.parseDouble(merchantLnglat[1]));
        Distance distance = new Distance(10, RedisGeoCommands.DistanceUnit.KILOMETERS);
        Circle circle = new Circle(point, distance);
        // 10km内在线骑手id集合
        List<Long> courierIds = new ArrayList<>();
        GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo().radius("onlin_courier", circle);
        // GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo().radius("location2",circle);
        List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> content = results.getContent();
        for (GeoResult<RedisGeoCommands.GeoLocation<Object>> geoResult:content){
            RedisGeoCommands.GeoLocation<Object> geoResultContent = geoResult.getContent();
            System.out.println("名字:"+geoResultContent.getName());
            String idStr = geoResultContent.getName().toString().split("_")[1];
            courierIds.add(Long.parseLong(idStr));
        }
        List<Courier> filteredCouriers = couriers.stream().filter(c -> courierIds.contains(c.getId())).toList();
        return filteredCouriers;
    }
}
